#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "Task.hpp"

const int N = 5;

template<class T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }

    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void threadWait()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }

    void threadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    bool isEmpty()
    {
        return _tasks.empty();
    }

public:
    ThreadPool(int num = N)
        :_num(num)
        ,_threads(num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond); 
    }

    //添加任务
    void pushTask(const T& t)
    {
        LockQueue();
        _tasks.push(t);
        //唤醒一下进程们
        threadWakeup();
        UnLockQueue();
    }

    //弹出任务
    T popTask()
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    void init()
    {

    }

    static void* threadRoutine(void* args)
    {
        //自动释放资源，不用等待了
        pthread_detach(pthread_self());
        ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);

        tp->LockQueue();
        while(tp->isEmpty())
        {
            tp->threadWait();
        }
        T t = tp->popTask();
        tp->UnLockQueue();

        
        
        t();
        cout << "format : "<< t.formatArg() << "result:" << t.formatRes() << endl;
        
    }

    void start()
    {
        for(int i = 0;i<_num;i++)
        {
            pthread_create(&_threads[i],nullptr,threadRoutine,this);
        }
    }

private:
    //1.存储线程的容器
    std::vector<pthread_t> _threads;
    //2.线程个数
    int _num;
    //3.任务队列
    std::queue<T> _tasks;
    //4.需要让线程在特定条件下等待，条件变量
    pthread_cond_t _cond;
    //5.一把锁保证队列安全
    pthread_mutex_t _mutex;
};